package com.atguigu4.transaction;

import com.atguigu.util.JDBCUtils;
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/*
 *
 * 2.事务处理的原则：保证所有事务都作为一个工作单元来执行，即使出现了故障，都不能改变这种执行方式。
 * 当在一个事务中执行多个操作时，要么所有的事务都被提交(commit)，那么这些修改就永久地保存
 * 下来；要么数据库管理系统将放弃所作的所有修改，整个事务回滚(rollback)到最初状态。
 *
 * 3.数据一旦提交，就不可回滚
 *
 * 4.哪些操作会导致数据的自动提交？
 * 		>DDL操作一旦执行，都会自动提交。
 * 			>set autocommit = false 对DDL操作失效
 * 		>DML默认情况下，一旦执行，就会自动提交。
 * 			>我们可以通过set autocommit = false的方式取消DML操作的自动提交。
 * 		>默认在关闭连接时，会自动的提交数据
 */
public class TransactionTest {

  // ******************未考虑数据库事务情况下的转账操作**************************
  /*
   * 针对于数据表user_table来说：
   * AA用户给BB用户转账100
   *
   * update user_table set balance = balance - 100 where user = 'AA';
   * update user_table set balance = balance + 100 where user = 'BB';
   */

  // 失败的数据库操作
  @Test
  public void testUpdate() {
    //    String sql1 = "update user_table set balance = balance - 100 where user = ?";
    //    update(sql1, "AA");
    //    // 模拟网络异常,所以只有A转出去，B没有转回来
    //    System.out.println(10 / 0);
    //    // 不可到达
    //    String sql2 = "update user_table set balance = balance + 100 where user = ?";
    //    update(sql2, "BB");
    //    System.out.println("转账成功");
  }

  @Test
  public void testUpdateWithTx() {
    Connection conn = null;
    try {
      conn = JDBCUtils.getConnection();
      System.out.println(conn.getAutoCommit()); // true
      // 1.取消数据的自动提交
      conn.setAutoCommit(false);

      String sql1 = "update user_table set balance = balance - 100 where user = ?";
      update(conn, sql1, "AA");

      // 模拟网络异常
      System.out.println(10 / 0);

      String sql2 = "update user_table set balance = balance + 100 where user = ?";
      update(conn, sql2, "BB");

      System.out.println("转账成功");

      // 2.真正提交数据
      conn.commit();

    } catch (Exception e) {
      e.printStackTrace();
      try {
        // 3.回滚数据
        conn.rollback();
      } catch (SQLException e1) {
        e1.printStackTrace();
      }
    } finally {
      JDBCUtils.closeResource(conn, null);
    }
  }

  // 通用的增删改操作---version 2.0 （考虑上事务）
  public int update(Connection conn, String sql, Object... args) {
    PreparedStatement ps = null;
    try {
      ps = conn.prepareStatement(sql);
      for (int i = 0; i < args.length; i++) {
        ps.setObject(i + 1, args[i]);
      }
      return ps.executeUpdate();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      JDBCUtils.closeResource(null, ps);
    }
    return 0;
  }
}
